package com.tian.service.impl.pay;


import com.tian.common.config.WXPayConfig;
import com.tian.common.enums.PayStatusEnum;
import com.tian.common.exception.BusinessException;
import com.tian.common.factory.ApplicationContextFactory;
import com.tian.common.util.StringUtil;
import com.tian.dto.pay.PayNotifyTestReqDto;
import com.tian.entity.ChargePayOrder;
import com.tian.service.pay.PayBaseService;
import com.tian.service.pay.PaymentService;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.h5.model.Transaction;
import com.wechat.pay.java.service.payments.h5.model.Amount;
import com.wechat.pay.java.service.payments.h5.model.PrepayRequest;
import com.wechat.pay.java.service.payments.h5.model.PrepayResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;

/**
 * {@code @description:} 微信支付接口实现类
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024-10-10 21:49
 * {@code @version:} 1.0
 */
@Slf4j
@Service("wxPaymentService")
public class WXPaymentServiceImpl implements PaymentService {
    //    @Resource
//    private H5Service h5Service;
    @Resource
    private WXPayConfig wxPayConfig;

    /**
     * 预支付充值订单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String prepay(ChargePayOrder chargePayOrder,String msg, Boolean isTest) {
        //组装支付参数
        PrepayResponse prepay = null;
        if (isTest) {
            prepay = new PrepayResponse();
            //测试环境，返回测试url
            prepay.setH5Url(chargePayOrder.getOrderNo());
        } else {
            PrepayRequest request = getPrepayRequest(chargePayOrder.getAmount(), msg, chargePayOrder.getOrderNo());
            //调用微信接口生成预付单
//            prepay = h5Service.prepay(request);
        }
        //返回失败
        if (prepay == null || StringUtil.isBlank(prepay.getH5Url())) {
            throw new BusinessException("支付失败");
        }
        return prepay.getH5Url();
    }


    private PrepayRequest getPrepayRequest( BigDecimal amount, String msg,String orderNo) {
        PrepayRequest request = new PrepayRequest();
        Amount payAmount = new Amount();
        payAmount.setTotal(amount.multiply(new BigDecimal(100)).intValue());
        payAmount.setCurrency("CNY");
        request.setAmount(payAmount);
        request.setMchid(wxPayConfig.getMerchantId());
        request.setDescription(msg);
        request.setNotifyUrl(wxPayConfig.getNotifyUrl());
        request.setOutTradeNo(orderNo);
        return request;
    }

    /**
     * 微信支付回调通知 ----- 支付结果通知
     */
    @Override
    public ResponseEntity<String> payNotify(HttpServletRequest request, PayNotifyTestReqDto payNotifyTestReqDto) {

        try {
            Transaction transaction = getTransaction(request, payNotifyTestReqDto);
            PayBaseService payBaseService = ApplicationContextFactory.getBean(PayBaseService.class);
            String orderNo = transaction.getOutTradeNo();
            Transaction.TradeStateEnum tradeState = transaction.getTradeState();
            if (Transaction.TradeStateEnum.SUCCESS.equals(tradeState)) {
                payBaseService.paySuccess(orderNo);
                return new ResponseEntity<>("success", HttpStatus.OK);
            } else if (Transaction.TradeStateEnum.USERPAYING.equals(tradeState)) {
                //支付中的不用做任何处理
                return new ResponseEntity<>("success", HttpStatus.OK);
            } else if (Transaction.TradeStateEnum.REFUND.equals(tradeState)) {
                // 更新支付订单状态REFUND
                payBaseService.payFailed(orderNo, PayStatusEnum.REFUND);
//                return new ResponseEntity<>("success", HttpStatus.OK);
            } else {
                // 更新支付订单状态FAILED
                payBaseService.payFailed(orderNo, PayStatusEnum.FAILED);
                return new ResponseEntity<>("success", HttpStatus.OK);
            }
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        } catch (ValidationException e) {
            // 签名验证失败，返回 401 UNAUTHORIZED 状态码
            log.error("wx pay sign verification failed", e);
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        } catch (IOException e) {
            log.error("wx pay parse request body failed", e);
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    private Transaction getTransaction(HttpServletRequest request, PayNotifyTestReqDto payNotifyTestReqDto) throws IOException {
        //test
        if (payNotifyTestReqDto != null) {
            Transaction transaction = new Transaction();
            transaction.setOutTradeNo(payNotifyTestReqDto.getOutTradeNo());
            Transaction.TradeStateEnum tradeStateEnum = "SUCCESS".equals(payNotifyTestReqDto.getTradeState()) ? Transaction.TradeStateEnum.SUCCESS : Transaction.TradeStateEnum.PAYERROR;
            transaction.setTradeState(tradeStateEnum);
            return transaction;
        }
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        String wechatPayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatPayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(getPostDataAsString(request))
                .build();
        // 初始化 RSAAutoCertificateConfig
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(wxPayConfig.getMerchantId())
                .privateKeyFromPath(wxPayConfig.getPrivateKeyPath())
                .merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())
                .apiV3Key(wxPayConfig.getKey())
                .build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        // 以支付通知回调为例，验签、解密并转换成 Transaction
        return parser.parse(requestParam, Transaction.class);
    }

    public String getPostDataAsString(HttpServletRequest request) throws IOException {
        StringBuilder postData = new StringBuilder();
        BufferedReader reader = request.getReader();
        String line;
        while ((line = reader.readLine()) != null) {
            postData.append(line);
        }
        return postData.toString();
    }
}
